﻿using System;
using System.Reflection;
using System.Text.RegularExpressions;

namespace _5E.Utils.WebHelper.Route
{
    public abstract class RouteManager : AjaxManager
    {
        private Assembly m_routeAssembly = null;
        private string m_routeTypeFormat = null;
        private string m_classMatchName = null;
        private string m_methodMatchName = null;
        private Regex m_routeMatchRegex = null;

        private RouteManager() { }

        public RouteManager(
            string routeAssemblyName,
            string routeTypeFormat,
            string classMatchName = "class",
            string methodMatchName = "method",
            string routeMatchRegexFormat = @"(?<{0}>\w+)\.(?<{1}>\w+)\.do")
        {
            m_routeAssembly = Assembly.Load(routeAssemblyName);
            m_routeTypeFormat = string.Format("{0}.{1}", routeAssemblyName, routeTypeFormat);
            m_classMatchName = classMatchName;
            m_methodMatchName = methodMatchName;
            m_routeMatchRegex = new Regex(string.Format(routeMatchRegexFormat, m_classMatchName, m_methodMatchName));
        }

        protected override Type MappingType
        {
            get
            {
                string typeName = string.Format(m_routeTypeFormat, GetUrlMatchValue(m_classMatchName));
                Type type = m_routeAssembly.GetType(typeName);
                if (null == type || !ValidateType(type))
                    RouteMatchError();
                return type;
            }
        }

        protected virtual bool ValidateType(Type type)
        {
            return true;
        }

        protected override MethodInfo MappingMethod
        {
            get
            {
                MethodInfo method = MappingType.GetMethod(GetUrlMatchValue(m_methodMatchName));
                if (null == method)
                    RouteMatchError();
                object[] attributes = method.GetCustomAttributes(typeof(RouteAttribute), false);
                if (0 == attributes.Length || !ValidateMethod(method))
                    RouteMatchError();
                return method;
            }
        }

        protected virtual bool ValidateMethod(MethodInfo method)
        {
            return true;
        }

        protected override object CreateInstance()
        {
            return Activator.CreateInstance(MappingType);
        }

        private string GetUrlMatchValue(string name)
        {
            Group group = m_routeMatchRegex.Match(Context.Request.AppRelativeCurrentExecutionFilePath).Groups[name];
            if (!group.Success)
                RouteMatchError();
            return group.Value;
        }

        protected virtual void RouteMatchError()
        {
            throw new RouteException(string.Format("{0}.{1}地址不存在或不可访问!",
                GetUrlMatchValue(m_classMatchName), GetUrlMatchValue(m_methodMatchName)));
        }
    }
}
